package com.sheng.leetcode.year2023.month05.day24;

import org.junit.Test;

/**
 * @author liusheng
 * @date 2023/05/24
 * <p>
 * 1377. T 秒后青蛙的位置<p>
 * <p>
 * 给你一棵由 n 个顶点组成的无向树，顶点编号从 1 到 n。青蛙从 顶点 1 开始起跳。规则如下：<p>
 * 在一秒内，青蛙从它所在的当前顶点跳到另一个 未访问 过的顶点（如果它们直接相连）。<p>
 * 青蛙无法跳回已经访问过的顶点。<p>
 * 如果青蛙可以跳到多个不同顶点，那么它跳到其中任意一个顶点上的机率都相同。<p>
 * 如果青蛙不能跳到任何未访问过的顶点上，那么它每次跳跃都会停留在原地。<p>
 * 无向树的边用数组 edges 描述，其中 edges[i] = [ai, bi] 意味着存在一条直接连通 ai 和 bi 两个顶点的边。<p>
 * 返回青蛙在 t 秒后位于目标顶点 target 上的概率。与实际答案相差不超过 10^-5 的结果将被视为正确答案。<p>
 * <p>
 * 示例 1：<p>
 * 输入：n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 2, target = 4<p>
 * 输出：0.16666666666666666<p>
 * 解释：上图显示了青蛙的跳跃路径。青蛙从顶点 1 起跳，第 1 秒 有 1/3 的概率跳到顶点 2 ，<p>
 * 然后第 2 秒 有 1/2 的概率跳到顶点 4，因此青蛙在 2 秒后位于顶点 4 的概率是 1/3 * 1/2 = 1/6 = 0.16666666666666666 。<p>
 * <p>
 * 示例 2：<p>
 * 输入：n = 7, edges = [[1,2],[1,3],[1,7],[2,4],[2,6],[3,5]], t = 1, target = 7<p>
 * 输出：0.3333333333333333<p>
 * 解释：上图显示了青蛙的跳跃路径。青蛙从顶点 1 起跳，有 1/3 = 0.3333333333333333 的概率能够 1 秒 后跳到顶点 7 。<p>
 * <p>
 * 提示：<p>
 * 1 <= n <= 100<p>
 * edges.length == n - 1<p>
 * edges[i].length == 2<p>
 * 1 <= ai, bi <= n<p>
 * 1 <= t <= 50<p>
 * 1 <= target <= n<p>
 * <p>
 * 来源：力扣（LeetCode）<p>
 * 链接：<a href="https://leetcode.cn/problems/frog-position-after-t-seconds">1377. T 秒后青蛙的位置</a><p>
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。<p>
 */
public class LeetCode1377 {

    @Test
    public void test01() {
//        int n = 7, t = 2, target = 4;
//        int[][] edges = {{1, 2}, {1, 3}, {1, 7}, {2, 4}, {2, 6}, {3, 5}};
//        int n = 7, t = 1, target = 7;
//        int[][] edges = {{1, 2}, {1, 3}, {1, 7}, {2, 4}, {2, 6}, {3, 5}};
        int n = 7, t = 20, target = 6;
        int[][] edges = {{1, 2}, {1, 3}, {1, 7}, {2, 4}, {2, 6}, {3, 5}};
        System.out.println(new Solution().frogPosition(n, edges, t, target));
    }
}

class Solution {

    double ans = 0;

    int[][] edges;

    int t;

    int target;

    public double frogPosition(int n, int[][] edges, int t, int target) {
        this.edges = edges;
        this.t = t;
        this.target = target;
        // 代表青蛙跳过的顶点
        int[] nums = new int[n + 1];
        nums[1] = 1;
        dfs(nums, 1, 0, 1, 0);
        return ans;
    }

    public void dfs(int[] nums, double probability, int cur, int index, int num) {
        num = 0;
        // 计算下次能跳跃的次数
        for (int[] edge : edges) {
            if (edge[0] == index && nums[edge[1]] == 0) {
                num++;
            } else if (edge[1] == index && nums[edge[0]] == 0) {
                num++;
            }
        }
        // 无法进行下一步，并且当前所在的顶点即是目标要求的 target
        if (num == 0) {
            if (index == target) {
                ans += probability;
            }
            return;
        }
        // 已经到达最终结点时，结束
        if (cur == t) {
            if (index == target) {
                ans += probability;
            }
            return;
        }
        // 继续进行下一层
        for (int[] edge : edges) {
            if (edge[0] == index && nums[edge[1]] == 0) {
                cur++;
                nums[edge[1]] = 1;
                dfs(nums, probability / num, cur, edge[1], num);
                // 回溯
                nums[edge[1]] = 0;
                cur--;
            } else if (edge[1] == index && nums[edge[0]] == 0) {
                cur++;
                nums[edge[0]] = 1;
                dfs(nums, probability / num, cur, edge[0], num);
                // 回溯
                nums[edge[0]] = 0;
                cur--;
            }
        }
    }
}
